package com.wb.listening

import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.wb.component.Slf4j
import com.wb.component.Slf4j.Companion.log
import com.wb.component.event.MsgSend
import com.wb.component.event.OnGroup
import com.wb.component.event.OnPrivate
import com.wb.component.filter.FunFilterAspect
import com.wb.config.AOPConfig
import com.wb.config.MessageFunConfig
import com.wb.entity.MsgGet
import com.wb.entity.RevokeMsg
import com.wb.exception.LseException
import com.wb.utils.VoiceToText
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
import org.springframework.scheduling.annotation.Async
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RestController
import java.io.File
import java.net.URLDecoder
import java.nio.charset.Charset
import javax.annotation.Resource
import javax.servlet.http.HttpServletRequest

@RestController
@Slf4j
@RequestMapping(value = arrayOf("/msg"))
open class MessageController : LseException() {

    @Resource
    lateinit var request: HttpServletRequest

    @Value("\${com.bot.voice.save.path}")
    lateinit var voicePath: String

    @RequestMapping(value = arrayOf("/do"))
    fun doIt(@RequestBody any: Any) {
        val gson = Gson()
        val str = gson.toJson(any)
        println(str)
        val map =
            gson.fromJson(str, object : TypeToken<HashMap<String, Any>>() {}.type)
                    as HashMap<String, Any>

        var revokeMsg: RevokeMsg? = null
        var msg: MsgGet? = null

        if (map.getOrDefault("type", "0").toString()
                .toBigDecimal().toInt() == 2005
        ) {
            revokeMsg = gson.fromJson(str, object : TypeToken<RevokeMsg>() {}.type)
        } else {
            msg = gson.fromJson(str, object : TypeToken<MsgGet>() {}.type)
            // 如果是语音消息 识别语音内容
            if (msg!!.type == 34) {
                val file = File(msg.msg)
                if (file.exists()) {
                    val targetFile = VoiceToText.saveToWav(file, File(voicePath, "${file.name}.wav"))
                    if (targetFile != null) {
                        log.info("开始音频转换 => wav")
                        var text = VoiceToText.toText(targetFile)
                        if (text != null) {
                            // 线上版本需要转换字符集 - 华硕win10
                            text = String(text.toByteArray(charset("GBK")), charset("UTF-8"))
                                .trim().replace(Regex("\\s"), "")
                            println("语音识别内容: ${text}")
                            msg.msg = text
                        }
                    }
                }
            }
        }

        val event = map.getOrDefault("event", "")
        runMethod(event, msg, revokeMsg)
    }

    @Async
    open fun runMethod(event: Any, msg: MsgGet?, revokeMsg: RevokeMsg?) {

        if (MessageFunConfig.eventMapMethod.containsKey(event)) {

            MessageFunConfig.eventMapMethod.get(event)!!.forEach { me, v ->

                val flag = FunFilterAspect.filter(me, msg)
                if (flag) {
                    val eventAnn = MessageFunConfig.eventMap.get(event)

                    val ann = me.getAnnotation(eventAnn)

                    if (ann is OnGroup) {
                        val groupAnn = ann as OnGroup
                        if (groupAnn.msgType != 0
                            && groupAnn.msgType != msg!!.type
                        ) {
                            print("群聊消息类型拦截 => 需要[${groupAnn.msgType}] 实际[${msg.type}]")
                            return@forEach
                        }
                    }

                    println("执行方法: ${me.name}")
                    val bean = AOPConfig.getBean(v)

                    if (me.parameterCount == 0) {
                        me.invoke(bean)
                        return@forEach
                    }
                    val args = arrayListOf<Any?>()
                    me.parameters.forEach {
//                        println("参数 => ${it.type}")
//                    val paramBean = it.type.getDeclaredConstructor().newInstance()
                        when (it.type.name) {
                            "com.wb.entity.MsgGet" -> args.add(msg)
                            "com.wb.entity.RevokeMsg" -> args.add(revokeMsg)
                            else -> args.add(null)
                        }
                    }

                    me.invoke(
                        bean,
                        *args.toArray()
                    )
                }

            }
        }


    }

}